#!/usr/bin/env perl

# 
# Copyright (c) 2002-2007 Eric Wallengren
# This file is part of the Continuous Automated Build and Integration 
# Environment (CABIE)
# 
# CABIE is distributed under the terms of the GNU General Public
# License version 2 or any later version.  See the file COPYING for copying 
# permission or http://www.gnu.org. 
#                                                                            
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR  
# IMPLIED, without even the implied warranty of MERCHANTABILITY or FITNESS 
# FOR A PARTICULAR PURPOSE.  ANY USE IS AT YOUR OWN RISK. 
#                                                                            
# Permission to modify the code and to distribute modified code is granted, 
# provided the above notices are retained, and a notice that the code was 
# modified is included with the above copyright notice. 
# 

BEGIN {push @INC, "./lib";}

require RPC::XML;
require RPC::XML::Client;

use Getopt::Std;

use Term::ReadLine;

my $prog;

my $server;
my $port;
my $login;
my $home;
my $password;
my $rpcargs;

my $salt = "c@b13";

my %Args;

my @cmdbuffer;

getopts('s:p:f:lih?', \%Args);

$cs = $Args{s};
$cp = $Args{p};
$h  = $Args{h};
$i  = $Args{i};
$f  = $Args{f};

#
# Special case, login
$login = $Args{l};

if (!defined($h)) {
    $h  = $Args{'?'};
}

$en   = $ENV{"BLDSERVER"};
$home = $ENV{"HOME"};

($es,$ep) = split(/:/, $en);

if (defined($h)) {
    usage();
}
 
if (defined($es)) {
    $server = $es;
}

if (defined($ep)) {
    $port = $ep;
}

if (defined($cs)) {
    $server = $cs;
}

if (defined($cp)) {
    $port = $cp;
}

if (defined($f)) {
    if (-f "$f") {
        open (IN, "<$f");
        @cmdbuffer = <IN>;
        close(IN);
    } 
}

if (defined($login)) {
    if (! -f "$home/.cabiepass") {
        my $prompt;
        open (PASS, ">$home/.cabiepass") || 
            die "unable to open password file\n";
        while ($prompt =~ /^$/) {
            print "Enter password: ";
            $prompt = <STDIN>;
            print "\n";
        }
        $password = crypt($prompt,$salt);
        print PASS "$server:$password\n";
        close(PASS);
        exit 0;
    }
}

if ($server =~ /^$/ || $port =~ /^$/) {
    usage();
}

if (defined($i)) {
    do_loop();
}

if (@ARGV == 0) {
    print "\nTry commands as an argument\n";
    usage();
}

sub helo {

    my $server = shift;
    my $port   = shift;

    $cli     = RPC::XML::Client->new("http://$server:$port");
    $request = RPC::XML::request->new("helo", $server);
    $resp    = $cli->send_request($request);

    if ($resp =~ /Connection refused/) {
        return 1;
    } else {
        return 0;
    }

}

#----------------------------------------------------------------------
# Client stuff
sub client_call {

    my $cmd  = shift;
    my $args = join(' ', @_);

    my @return = ();

    $cli     = RPC::XML::Client->new("http://$server:$port");
    $request = RPC::XML::request->new($cmd, $args);
    $resp    = $cli->send_request($request);

    if ($resp =~ /Connection refused/) {
        error("can't connect", $server, $port);
    } else {
        @return = @{$resp->value};
        push @return, "\n";
        return @return;
    }

}

sub usage {
    print "\nbuild -s server -p port [-i interactive mode] command ".
          "[options]\n";
    exit 1;
}

sub do_loop {

    my %Opts;

    my $cnt = 1;

    my $bRecord   = 0;
    my $bPlayback = 0;
    my $oldserver = "";
    my $oldport   = 0;

    my $prompt;

    my @argstring;

    if (@cmdbuffer > 0) {
        $bPlayback = 1;
    }

    my $term   = new Term::ReadLine 'CABIE Client';
    my $OUT    = $term->OUT || \*STDOUT;

    my @empty;

    if (helo($server, $port)) {
        error("can't connect", $server, $port);
    }

    print "\nEntering interactive mode, Type 'quit' to exit\n";
    while ($command !~ /^[Qq][Uu][Ii][Tt]$/) {
        @argstring = ();
        $prompt = "[$server:$port]";
        if ($bPlayback) {
            if ($bRecord) {
                print "Cannot replay while in record mode\n";
                $command = "";
            } else {
                foreach $one (@cmdbuffer) {
                    chomp $one;
                    ($server, $port, $command) = split(/:/, $one);
                    if ($oldserver !~ /^$server$/ || $oldport != $oldport) {
                        if (helo($server, $port)) {
                            error("can't connect", $server, $port);
                        }
                    } 
                    $oldserver = $server;
                    $oldport = $port;
                    @argstring = split(/ /, $command);
                    @answer = client_call(@argstring);
                    print STDOUT @answer;
                }
            } 
            $bPlayback = 0;
        } else {
            $command = $term->readline($prompt." $cnt >> ");
            $term->addhistory($command) if /\S/;
            chomp $command;
            @command = @empty;
            push @command, $command;
        }
        if ($bRecord) {
            if ($command !~ /^stop/) {
                push @cmdbuffer, "$server:$port:$command";
            }
        }
        if ($command !~ /^quit$/ ) {
            #
            # See if we're making a local system call
            #
            if ($command =~ /^!/) {
                $command =~ s/^!//g; 
                system("$command");
            } elsif ($command =~ /\*/) {
                @commands = split(/\*[ +]/, $command);
                foreach $entry (@commands) {
                    print "\n";
                    @argstring = split(/ /, $command);
                    @answer = client_call(@argstring);
                    print @answer;
                }
            } elsif ($command =~ /^connect /) {
                @_  = split(/ /, $command);
                $oserver = $server;
                $oport   = $port;
                shift;
                @ARGV = @_;
                getopts('s:p:', \%Opts);
                $s = $Opts{s};
                $p = $Opts{p};
                if (defined($s)) {
                    $server = $s;
                    $prompt = "[$server:$port]";
                }
                if (defined($p)) {
                    $port   = $p;
                }
                if (helo($server, $port)) {
                    error("can't connect", $server, $port);
                }
            } elsif ($command =~ /^save /) {
                @_  = split(/ /, $command);
                shift;
                @ARGV = @_;
                getopts('f:', \%Opts);
                $f = $Opts{f};
                if (!defined($f)) {
                    print "No file specified\n";
                } else {
                    open (OUT, ">$f");
                    foreach $one (@cmdbuffer) {
                        print OUT "$one\n";
                    }
                }
            } elsif ($command =~ /^record$/) {
                @cmdbuffer = @empty;
                $bRecord = 1;
            } elsif ($command =~ /^stop$/) {
                $bRecord = 0;
            } elsif ($command =~ /^replay$/) {
                if (@cmdbuffer == 0) {
                    print "No commands to replay\n";
                } else {
                    $bPlayback = 1;
                }
            } else {
                @argstring = split(/ /, $command);
                @answer = client_call(@argstring);
                print STDOUT @answer;
            }
            if ($command !~ /^$/) {
                $cnt++;
            }
        } else {
            exit(0);
        }
    }
}
    
sub error {

    my $msg    = shift;
    my $server = shift;
    my $port   = shift;

    print "\nCan't connect to $server on port $port\n";

    exit 1;

}

if (helo($server, $port)) {
    print "Couldn't connect to $server on $port\n";
} else {
    print client_call(@ARGV);
}

exit(0);
